/* Display.cc -- Mostra as informações de jogo no terminal
 *
 * Copyright (C) 2008, Diogo F. S. Ramos <diogo.ramos@usp.br>
 * GEAR - Grupo de Estudos Avançados em Robótica
 * <http://www.sel.eesc.usp.br/gear>
 *
 * This file is part of GEARMedula.
 * 
 * GEARMedula is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 3 of the
 * License.
 * 
 * GEARMedula is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <time.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#include "Display.hh"
#include "Monitor.hh"
#include "GEARMedulaIDL.hh"

char * buff;
size_t buff_size;

Display::Display()
{
}

Display::~Display()
{
    endNCurses();
}

void
Display::Init( Monitor * monitor )
{
    /* Iniciando o mundo */
    world_.resize( LENGTH_WORLD_VECTOR, 0.0 );
    world_window_ = NULL;
    
    /* Iniciando field */
    field_.resize( LENGTH_FIELD_VECTOR, 0.0 );
    field_window_ = NULL;
    
    enable_ = 1;
    pthread_mutex_init( &(enable_mutex_),
			NULL );

    monitor_ = monitor;
}

void
Display::Run( void * ptr )
{
    initNCurses();

    while( 1 )
    {
	monitor_->getWorld( world_ );
	worldWindowUpdate();

	monitor_->getField( field_ );
	fieldWindowUpdate();

	errinfWindowUpdate();

	wrefresh( world_window_ );
	wrefresh( field_window_ );
	wrefresh( errinf_window_ );
	sleep(1);
    }
}

void
Display::initNCurses()
{
    int col;
    int row;
    char mesg0[] = "GEAR - Grupo de Estudos Avançados em Robótica";
    char mesg1[] = "GEARMedula - Servidor";

    initscr();

    getmaxyx(stdscr,row,col);
    mvprintw(1,(col-strlen(mesg0))/2,"%s",mesg0);
    mvprintw(2,(col-strlen(mesg1))/2,"%s",mesg1);
    border('|', '|', '-', '-', '+', '+', '+', '+');
    refresh();

    worldWindowInit(  );

    fieldWindowInit(  );

    errinfWindowInit(  );
}

void
Display::endNCurses()
{
    delwin( world_window_ );
    delwin( field_window_ );
    delwin( errinf_window_ );
    endwin();
}

void
Display::worldWindowInit()
{
    int row = 0;
    int col = 0;
    
    w_x0_pos_ = 5;
    w_y0_pos_ = 3;    
    w_x_inc_ = 8;
    world_nlines_ = 19;
    world_startx_ = 4;

    world_window_ = newwin( world_nlines_,
			    COLS/2,
			    world_startx_,
			    1);
    getmaxyx(world_window_,row,col);
    mvwprintw(world_window_,1,(col-strlen("WORLD"))/2,"%s", "WORLD");
    
    mvwprintw(world_window_,4,2,"x0");
    mvwprintw(world_window_,5,2,"y0");
    mvwprintw(world_window_,6,2,"x1");
    mvwprintw(world_window_,7,2,"y1");
    mvwprintw(world_window_,8,2,"x2");
    mvwprintw(world_window_,9,2,"y2");
    mvwprintw(world_window_,10,2,"x3");
    mvwprintw(world_window_,11,2,"y3");

    mvwprintw(world_window_,w_y0_pos_,w_x0_pos_,"Mu");
    mvwprintw(world_window_,w_y0_pos_,w_x0_pos_ + (w_x_inc_*1),"Ca");
    mvwprintw(world_window_,w_y0_pos_,w_x0_pos_ + (w_x_inc_*2),"Me");
    mvwprintw(world_window_,w_y0_pos_,w_x0_pos_ + (w_x_inc_*3),"G0");
    mvwprintw(world_window_,w_y0_pos_,w_x0_pos_ + (w_x_inc_*4),"G1");

    box(world_window_, 0, 0);
}

void
Display::fieldWindowInit()
{
    int row = 0;
    int col = 0;
    
    f_x0_pos_ = 5;
    f_y0_pos_ = 3;    
    f_x_inc_ = 8;
    field_nlines_ = 19;
    field_startx_ = 4;

    field_window_ = newwin(field_nlines_,
				COLS/2-1,
				field_startx_,
				COLS/2+1);
    getmaxyx(field_window_,row,col);
    mvwprintw(field_window_,1,(col-strlen("FIELD"))/2,"%s", "FIELD");

    mvwprintw(field_window_,f_y0_pos_,f_x0_pos_,"px");
    mvwprintw(field_window_,f_y0_pos_,f_x0_pos_ + (f_x_inc_*1),"py");
    mvwprintw(field_window_,f_y0_pos_,f_x0_pos_ + (f_x_inc_*2),"pa");


    mvwprintw(field_window_,4,2,"G0");
    mvwprintw(field_window_,5,2,"G1");
    mvwprintw(field_window_,6,2,"G2");
    mvwprintw(field_window_,7,2,"G3");
    mvwprintw(field_window_,8,2,"G4");

    mvwprintw(field_window_,10,2,"A0");
    mvwprintw(field_window_,11,2,"A1");
    mvwprintw(field_window_,12,2,"A2");
    mvwprintw(field_window_,13,2,"A3");
    mvwprintw(field_window_,14,2,"A4");

    mvwprintw(field_window_,16,2,"BL");

    
    box(field_window_, 0, 0);
}

void
Display::errinfWindowInit()
{
    int row = 0;
    int col = 0;

    getmaxyx(world_window_,row,col);
    errinf_window_ = newwin( LINES-field_nlines_-field_startx_-1,
			     COLS-2,
			     field_startx_ + field_nlines_,
			     1 );
    scrollok( errinf_window_, 1 );

    /* Aqui vai uma das maiores proezas da humanidade! */
    fclose( stderr );
    stderr = open_memstream( &buff, &buff_size );
}

void
Display::worldWindowSetPos( int x, int y, float data)
{
    mvwprintw(world_window_,
	      (w_y0_pos_+1) + y,
	      (w_x0_pos_) + (w_x_inc_ * x),
	      "%.2f",data);
}

void
Display::fieldWindowSetPos( int x, int y, float data)
{
    mvwprintw(field_window_,
	      (f_y0_pos_+1) + y,
	      (f_x0_pos_) + (f_x_inc_ * x),
	      "%.2f",data);
}

void
Display::fieldWindowUpdate()
{
    int i = 0;
    int j = 0;
    int index = 0;

    /* Robôs */
    for( i = 0 ; i < 11 ; i++ )
    {
	if( i == 5 )
	    i++;
	for( j = 0 ; j < 3 ; j++ )
	{
	    fieldWindowSetPos( j,
			       i,
			       field_[index+2] );
	    index++;
	}
    }

    /* Bola */
    for( i = 0 ; i < 2 ; i++ )
	fieldWindowSetPos( i,
			   12,
			   field_[i] );

}

void
Display::worldWindowUpdate()
{
    int i = 0;

    /* Mundo */
    for( i = 0 ; i < 8 ; i++ )
	worldWindowSetPos( 0,
			   i,
			   world_[i] );

    /* Campo */
    for( i = 0 ; i < 8 ; i++ )
	worldWindowSetPos( 1,
			   i,
			   world_[i+8] );

    /* Meio */
    for( i = 0 ; i < 4 ; i++ )
	worldWindowSetPos( 2,
			   i,
			   world_[i+16] );

    /* Gol 0 */
    for( i = 0 ; i < 4 ; i++ )
	worldWindowSetPos( 3,
			   i,
			   world_[i+20] );

    /* Gol 1 */
    for( i = 0 ; i < 4 ; i++ )
	worldWindowSetPos( 4,
			   i,
			   world_[i+24] );
}


void
Display::errinfWindowUpdate()
{
    wprintw( errinf_window_, "%s", buff);
    fflush( stderr );
    rewind( stderr );
    fflush( stderr );
}
